//写一个函数，输入 n ，求斐波那契（Fibonacci）数列的第 n 项（即 F(N)）。斐波那契数列的定义如下： 
//
// 
//F(0) = 0,   F(1) = 1
//F(N) = F(N - 1) + F(N - 2), 其中 N > 1. 
//
// 斐波那契数列由 0 和 1 开始，之后的斐波那契数就是由之前的两数相加而得出。 
//
// 答案需要取模 1e9+7（1000000007），如计算初始结果为：1000000008，请返回 1。 
//
// 
//
// 示例 1： 
//
// 
//输入：n = 2
//输出：1
// 
//
// 示例 2： 
//
// 
//输入：n = 5
//输出：5
// 
//
// 
//
// 提示： 
//
// 
// 0 <= n <= 100 
// 
//
// Related Topics 记忆化搜索 数学 动态规划 👍 501 👎 0


package leetcode.editor.cn;

import javax.swing.plaf.BorderUIResource;
import java.sql.PreparedStatement;

class 斐波那契数列 {
    public static void main(String[] args) {
        Solution solution = new 斐波那契数列().new Solution();
        System.out.println(solution.fib(8));
    }

    //leetcode submit region begin(Prohibit modification and deletion)
    class Solution {

        public int fib(int n) {
            if (n < 2) return n;
            int[][] q = {{0, 1}, {1, 1}};
            int[][] res = pow(q, n - 1);
            return res[1][1];
        }

        private int[][] pow(int[][] a, int n) {
            int[][] ret = {{1, 0}, {0, 1}};
            while (n > 0) {
                if ((n & 1) == 1) {
                    ret = multiply(ret, a);
                }
                n >>= 1;
                a = multiply(a, a);
            }
            return ret;
        }

        private int[][] multiply(int[][] a, int[][] b) {
            int[][] c = new int[2][2];
            for (int i = 0; i < 2; i++) {
                for (int j = 0; j < 2; j++) {
                    c[i][j] = (int) (((long) a[i][0] * b[0][j] + (long) a[i][1] * b[1][j]) % 1000000007);
                }
            }
            return c;
        }


        int times, n;

        public int fib1(int n) {
            if (n < 2) return n;
            this.n = n;
            times = 1;
            return rec(0, 1);
        /*int[] dp = new int[n+1];
        dp[0] = 0;
        dp[1] = 1;
        for (int i = 2; i <= n; i++) {
            dp[i] = (dp[i - 1] + dp[i - 2]) % 1000000007;
        }
        return dp[n];*/
        }

        private int rec(int a, int b) {
            if (times++ == n) return b;
            return rec(b, (a + b) % 1000000007);
        }
    }
//leetcode submit region end(Prohibit modification and deletion)

}
